from matplotlib import pyplot as plt
from xlwt import Workbook
from numpy import linspace, pi, exp
from datetime import datetime
from scipy.stats import norm
from mpl_toolkits import axisartist
from random import randint
from tkinter import Tk, Frame, Label, Entry, Text, Button, IntVar, Radiobutton, Checkbutton, messagebox, StringVar

plt.rcParams['axes.unicode_minus'] = False


def save():
    n = int(eval(var[0].get()))
    book = Workbook(encoding='utf-8', style_compression=0)
    sheet = book.add_sheet('二维表', cell_overwrite_ok=True)
    row = [0.01 * i for i in range(10)]
    column = [0.1 * i for i in range(31)]
    for i in range(len(row)):
        sheet.write(0, i + 1, row[i])
    for i in range(len(column)):
        sheet.write(i + 1, 0, column[i])
    for i in range(len(row)):
        for j in range(len(column)):
            data = norm.cdf(row[i] + column[j])
            sheet.write(j + 1, i + 1, round(data, n))

    sheet1 = book.add_sheet('一维表', cell_overwrite_ok=True)
    x = [0.01 * i for i in range(310)]
    y = [norm.cdf(i) for i in x]
    for i in range(310):
        sheet1.write(i, 0, x[i])
        sheet1.write(i, 1, round(y[i], n))
    time__ = str(datetime.now().minute) + '-' + str(datetime.now().second)
    book.save(f'标准正态分布表{time__}.xls')
    messagebox.showinfo(title='提示！', message=f'生成完成！\n标准正态分布表{time__}.xls 保存在程序同级目录！')


# pdf 已知值(负无穷到正无穷），返回概率（0到0.4）
# cdf 已知值(负无穷到正无穷），返回累计概率（0到1）
# ppf 已知累计概率（0到1），返回值(负无穷到正无穷）
def n_pdf():  # 查表(已知值）
    n = int(eval(var[0].get()))
    x0 = eval(var[1].get())
    if x0 < -3 or x0 > 3:
        messagebox.showinfo(title='提示！', message='建议范围是[-3,3],参考3σ原则。')
    plt.figure()
    plt.subplot(1, 2, 1)
    x = linspace(start=-4, stop=4, num=800)
    y = norm.pdf(x)
    plt.plot(x, y, color='g')
    y0 = norm.pdf(x0)
    plt.plot(x0, y0, color='r', marker='o')
    plt.fill_between(x, y, where=(x <= x0), color='lightblue')
    plt.title(f'X值:{x0}\n概率:{y0}')

    plt.subplot(1, 2, 2)
    x = linspace(start=-4, stop=4, num=800)
    y = norm.cdf(x)
    plt.plot(x, y, color='g')
    y1 = norm.cdf(x0)
    plt.plot(x0, y1, color='r', marker='o')
    # plt.fill_between(x, y, where=(y <= y1), color='lightblue')
    plt.title(f'X值:{x0}\n累计概率:{y1}')
    var[1].set(round(x0, n))
    var[2].set(round(y0, n))
    var[3].set(round(y1, n))
    plt.show()


def n_ppf():  # 反查表(已知累计概率）
    n = int(eval(var[0].get()))
    y0 = eval(var[6].get())
    if y0 <= 0 or y0 >= 1:
        messagebox.showinfo(title='提示！', message='建议范围是(0,1),参考概率取值范围。')
    plt.figure()
    plt.subplot(1, 2, 2)
    x = linspace(start=-4, stop=4, num=800)
    y = norm.cdf(x)
    plt.plot(x, y, color='g')
    x0 = norm.ppf(y0)
    plt.plot(x0, y0, color='r', marker='o')
    # plt.fill_between(x, y, where=(y <= y0), color='lightblue')
    plt.title(f'X值:{x0}\n累计概率:{y0}')

    plt.subplot(1, 2, 1)
    x = linspace(start=-4, stop=4, num=800)
    y = norm.pdf(x)
    plt.plot(x, y, color='g')
    y1 = norm.pdf(x0)
    plt.plot(x0, y1, color='r', marker='o')
    plt.fill_between(x, y, where=(x <= x0), color='lightblue')
    plt.title(f'X值:{x0}\n概率:{y1}')
    var[4].set(round(x0, n))
    var[5].set(round(y1, n))
    var[6].set(round(y0, n))
    plt.show()


def draw():
    fig = plt.figure()
    ax = axisartist.Subplot(fig, 111)
    fig.add_axes(ax)
    ax.axis["bottom"].set_axisline_style("->", size=1.5)
    ax.axis["left"].set_axisline_style("->", size=1.5)
    ax.axis["top"].set_visible(False)
    ax.axis["right"].set_visible(False)

    n = float(eval(var[7].get()))
    if n <= 0 or n > 3:
        messagebox.showinfo(title='提示！', message='建议范围是(0,3],参考3σ原则。')
    cig = 40
    miu = 150
    # 绘制σ=40,μ=150的正态分布
    x = linspace(0, 300, 1000)
    y = 1 / (cig * (2 * pi) ** 0.5) * exp(-(x - miu) ** 2 / (2 * cig ** 2))
    plt.plot(x, y, color='blue')
    plt.fill_between(x, y, where=(x < miu), color='limegreen', alpha=0.6, )
    plt.fill_between(x, y, where=(x < miu + n * cig) & (x > miu), color='green', alpha=0.6, )
    plt.xlabel('库存量')
    plt.ylabel('概率')
    plt.xticks([])
    plt.yticks([])
    plt.title(f'N({miu},{cig}^2)')
    y_min = 0.04
    y_max0 = 95 / (cig * (2 * pi) ** 0.5) * exp(-(miu - miu) ** 2 / (2 * cig ** 2))
    plt.axvline(miu, y_min, y_max0, ls='--', c='white')
    y_max1 = 100 / (cig * (2 * pi) ** 0.5) * exp(-(n * cig) ** 2 / (2 * cig ** 2))
    plt.axvline(miu + n * cig, y_min, y_max1, ls='--', c='red')
    plt.axhline(y_max1 / 100, 0.05 * (miu + n * cig) / 100, (miu + n * cig) / 310, ls='--', c='y')
    plt.text(x=0.88 * miu, y=max(y), s='平均库存')
    plt.text(x=1.02 * miu, y=max(y) * 0.2, s='安全库存')
    plt.text(x=miu - n * cig - 60, y=y_max1 / 100 * 1.15, s='服务水平α')
    plt.annotate(text='最大库存', xy=(miu + n * cig, y_max1 / 200), xytext=(250, 0.005), weight='bold',
                 arrowprops=dict(arrowstyle='-|>', connectionstyle='arc3', color='red'),
                 bbox=dict(boxstyle='round,pad=0.5', fc='white', ec='k', lw=1, alpha=0.4))
    plt.show()


def mat():
    d_ = float(eval(var[8].get()))
    d_d = float(eval(var[9].get()))
    l_ = float(eval(var[10].get()))
    d_l = float(eval(var[11].get()))
    s_ = float(eval(var[12].get()))
    if s_ < 0.5 or s_ >= 1:
        messagebox.showinfo(title='提示！', message='建议范围是(0.5,1),参考概率密度反函数取值。')
    dx = (l_ * d_d ** 2 + d_ ** 2 * d_l ** 2) ** 0.5  # 混合标准差
    z = norm.ppf(s_)
    safe = dx * z
    x0 = [0.001 * i for i in range(499, 1005)]
    y0 = list(map(lambda x: norm.ppf(x) * dx, x0))
    plt.plot(x0, y0, color='g')
    if 0.5 <= s_ <= 1:
        plt.plot(s_, safe, marker='o', color='r')
        plt.text(s_, safe, s=f'安全库存{safe}')
    plt.title(f'安全库存随服务水平变化曲线图\n混合标准差{dx}')
    plt.xlabel('服务水平')
    plt.ylabel('安全库存')
    plt.show()


customer_purchase, members, supply_chain_members, color, g = [], [], [], [], 0


def func():
    class SupplyChainMember:
        def __init__(self):
            self.purchase = []  # 购买量或生产量
            self.percent_change = []  # 购买量或生产量波动百分比
            self.demand = []  # 需求量
            self.open_inventory = []  # 期初库存
            self.close_inventory = []  # 期末库存

    global customer_purchase, members, supply_chain_members, g, color
    try:
        middlemen_numbers = list(var[13].get().split())  # 中间商名称
    except:
        middlemen_numbers = []
        messagebox.showinfo(title='提示！', message='中间商名称以‘空格’隔开！')
        exit()
    try:
        customer_purchase = list(map(lambda _: float(_), var[14].get().split()))  # 客户购买量
    except:
        messagebox.showinfo(title='提示！', message='每一期客户购买量以‘空格’隔开！')
        exit()
    supply_chain_members = ['客户'] + middlemen_numbers + ['生产商']  # 供应链成员名字
    members = [SupplyChainMember() for _ in range(len(supply_chain_members))]  # 供应链成员对象
    g = len(supply_chain_members)
    color = g * ['r', 'g', 'b', 'c', 'm', 'y']
    # a．需求＝下游客户购买的数量；
    # b．一周的期初存货=前一周的期末存货；（第一次为客户购买量）
    # c．本周的期末存货=本周的需求；（当购买量等于0时，修正：本周的期末存货=期初存货-本周的需求）
    # d．购买的单位数=需求加上库存中的任何变化，购买量=需求+（期末存货-期初存货）；（当购买量小于零时，取0，并修正期末存货）
    # e. 购买数量波动百分比：购买数量波动百分比 = (本周购买量 − 上周购买量) / 上周购买量 × 100%；（第一次为0）
    for purchase in customer_purchase:
        members[0].purchase.append(purchase)
        for i in range(1, g):
            members[i].demand.append(members[i - 1].purchase[-1])
            if members[i].close_inventory:
                members[i].open_inventory.append(members[i].close_inventory[-1])
            else:
                members[i].open_inventory.append(members[0].purchase[0])
            members[i].close_inventory.append(members[i].demand[-1])
            will_purchase = members[i].demand[-1] + (members[i].close_inventory[-1] - members[i].open_inventory[-1])
            if will_purchase > 0:
                members[i].purchase.append(will_purchase)
            else:
                members[i].purchase.append(0.0)
                members[i].close_inventory[-1] = members[i].open_inventory[-1] - members[i].demand[-1]
    for member in members:
        member.percent_change.append(0.0)
        for i in range(1, len(customer_purchase)):
            if member.purchase[i - 1] != 0:
                member.percent_change.append((member.purchase[i] - member.purchase[i - 1]) / member.purchase[i - 1])
            else:
                member.percent_change.append(20)  # 当除数为0时，设定变化百分比正无穷为20

    sheet = [['供应链成员', '项目'] + ['第{}期'.format(i + 1) for i in range(len(customer_purchase))],
             ['客户', '购买量'] + [i for i in members[0].purchase],
             ['客户', '购买波动'] + [i for i in members[0].percent_change],
             [' ' for _ in range(len(customer_purchase) + 2)]]
    for i in range(1, g):
        sheet.append([supply_chain_members[i], '需求量'] + [j for j in members[i].demand])
        sheet.append([supply_chain_members[i], '期初库存'] + [j for j in members[i].open_inventory])
        sheet.append([supply_chain_members[i], '期末库存'] + [j for j in members[i].close_inventory])
        if i != g - 1:
            sheet.append([supply_chain_members[i], '购买量'] + [j for j in members[i].purchase])
            sheet.append([supply_chain_members[i], '购买波动'] + [j for j in members[i].percent_change])
            sheet.append([' ' for _ in range(len(customer_purchase) + 2)])
        else:
            sheet.append([supply_chain_members[i], '生产量'] + [j for j in members[i].purchase])
            sheet.append([supply_chain_members[i], '生产波动'] + [j for j in members[i].percent_change])
    book = Workbook(encoding='utf-8', style_compression=0)
    sheet0 = book.add_sheet('纵向表', cell_overwrite_ok=True)
    for i in range(len(sheet)):
        for j in range(len(sheet[0])):
            sheet0.write(i, j, sheet[i][j])
    sheet1 = book.add_sheet('横向表', cell_overwrite_ok=True)
    for i in range(len(sheet)):
        for j in range(len(sheet[0])):
            sheet1.write(j, i, sheet[i][j])
    time__ = str(datetime.now().minute) + '-' + str(datetime.now().second)
    book.save(f'牛鞭效应运算结果表{time__}.xls')
    for i in [b1, b2, b3, b4]:
        i.config(state='normal')
    messagebox.showinfo(title='提示', message=f'处理完成，表格牛鞭效应运算结果表{time__}.xls保存在程序的同级目录！')


def func1():
    for i in range(g):
        # fig = plt.figure(figsize=(8, 5), dpi=250)
        plt.plot(members[i].purchase, label=supply_chain_members[i], marker='o', color=color[i])
        for x, y in enumerate(members[i].purchase):
            plt.text(x, y, y)
        plt.legend()
        plt.title('{}{}量变化折线图'.format(supply_chain_members[i], '购买' if i != (g - 1) else '生产'))
        plt.xlabel('时间')
        plt.ylabel('{}量'.format('购买' if i != (g - 1) else '生产'))
        plt.show()
        # fig.savefig('{}{}{}量变化折线图'.format(i, supply_chain_members[i], '购买' if i != (n - 1) else '生产'))


def func2():
    # fig = plt.figure(figsize=(10, 6), dpi=200)
    for i in range(g):
        plt.plot(members[i].purchase, label=supply_chain_members[i], marker='o')
        for x, y in enumerate(members[i].purchase):
            plt.text(x, y, y)
    plt.legend()
    plt.title('供应链成员购买或生产量变化折线图')
    plt.xlabel('时间')
    plt.ylabel('购买或生产量')
    plt.show()
    # fig.savefig('{}供应链购买或生产量变化折线图'.format(n))


def func3():
    # fig = plt.figure(figsize=(12, 7), dpi=170)
    percent = []
    for i in range(len(supply_chain_members)):
        percent = list(map(lambda a: round(100 * a, 2), members[i].percent_change))
        plt.plot(percent, label=supply_chain_members[i], marker='s')
        for x, y in enumerate(percent):
            plt.text(x, y, y)
    y_max = list(set(percent))
    y_max.sort()
    if y_max[-1] == 2000:
        plt.ylim(ymax=y_max[-2] + 0.1 * (y_max[-1] - y_max[-2]))
    else:
        pass
    plt.legend()
    plt.title('供应链成员购买或生产量波动百分比折线图')
    plt.xlabel('时间(期)')
    plt.ylabel('百分比(%)')
    plt.show()
    # fig.savefig('{}供应链购买或生产量波动百分比折线图'.format(n + 1))


def func4():
    # fig = plt.figure(figsize=(12, 7), dpi=170)
    x, y, n_ = [], [], 0
    for i in range(g):
        for j in members[i].purchase:
            x.append(n_)
            n_ += 1
            y.append(j)
    plt.plot(x, y, marker='*', color=color[g + 1])
    for i in range(len(x)):
        if i >= 1:
            if not y[i] == y[i - 1]:
                plt.text(x[i], y[i], y[i])
    origin = [i + int(len(customer_purchase) / 2) for i in range(len(x)) if i % len(customer_purchase) == 0]
    labels = [supply_chain_members[int(i / len(customer_purchase))] for i in origin]
    plt.xticks(origin, labels)
    plt.title('逐级购买量或生产量放大的牛鞭效应图')
    plt.xlabel('供应链成员')
    plt.ylabel('购买量或生产量')
    plt.show()
    # fig.savefig('{}最终牛鞭效应图'.format(n + 2))
    # messagebox.showinfo(title='提示', message='处理完成，图表保存在程序的同级目录！')


root = Tk()
_w, _h = 500, 700
root.geometry(f'{_w}x{_h}+{int((root.winfo_screenwidth() - _w) / 2)}+{int((root.winfo_screenheight() - _h) / 2)}')
root.title("供应链管理 2022-12-18 by：wld")
var = [StringVar() for i in range(15)]

Label(root, text='正态分布制表与查询', font=("宋体", 15), fg="green").pack(side='top')
frame_0 = Frame(root)
frame_0.pack(side='top')
Label(frame_0, text="小数位数", font=("宋体", 15)).pack(side='left')
Entry(frame_0, textvariable=var[0], font=("宋体", 15), width=2, justify='center').pack(side='left')
var[0].set('4')
Button(frame_0, text="生成表格", font=("宋体", 12), fg="blue", command=save).pack(side='left')

frame_1 = Frame(root)
frame_1.pack(side='top')
Label(frame_1, text="X值", font=("宋体", 15)).pack(side='left')
Entry(frame_1, textvariable=var[1], font=("宋体", 15), width=8, justify='center').pack(side='left')
var[1].set('0.00')
Label(frame_1, text="概率", font=("宋体", 15)).pack(side='left')
Entry(frame_1, textvariable=var[2], font=("宋体", 15), width=8, justify='center', state='disabled').pack(side='left')
var[2].set('0.40')
Label(frame_1, text="累计概率", font=("宋体", 15), fg="black").pack(side='left')
Entry(frame_1, textvariable=var[3], font=("宋体", 15), width=8, justify='center', state='disabled').pack(side='left')
var[3].set('0.50')
Button(frame_1, text="计算绘图", font=("宋体", 12), fg="blue", command=n_pdf).pack(side='left')

frame_1_ = Frame(root)
frame_1_.pack(side='top')
Label(frame_1_, text="X值", font=("宋体", 15), fg="black").pack(side='left')
Entry(frame_1_, textvariable=var[4], font=("宋体", 15), width=8, justify='center', state='disabled').pack(side='left')
var[4].set('0.00')
Label(frame_1_, text="概率", font=("宋体", 15), fg="black").pack(side='left')
Entry(frame_1_, textvariable=var[5], font=("宋体", 15), width=8, justify='center', state='disabled').pack(side='left')
var[5].set('0.40')
Label(frame_1_, text="累计概率", font=("宋体", 15), fg="black").pack(side='left')
Entry(frame_1_, textvariable=var[6], font=("宋体", 15), width=8, justify='center').pack(side='left')
var[6].set('0.50')
Button(frame_1_, text="计算绘图", font=("宋体", 12), fg="blue", command=n_ppf).pack(side='left')

Label(root, text='-' * 50, font=("宋体", 15)).pack(side='top')
Label(root, text='需求不确定的库存控制绘图', font=("宋体", 15), fg="green").pack(side='top')
frame_2 = Frame(root)
frame_2.pack(side='top')
Label(frame_2, text="最大库存量=μ(150)+σ(40)的倍数", font=("宋体", 15)).pack(side='left')
Entry(frame_2, textvariable=var[7], font=("宋体", 15), width=8, justify='center').pack(side='left')
var[7].set('1.5')
Button(frame_2, text="库存量图", font=("宋体", 12), fg="blue", command=draw).pack(side='left')

Label(root, text='-' * 50, font=("宋体", 15)).pack(side='top')
Label(root, text='供需不确定的安全库存计算', font=("宋体", 15), fg="green").pack(side='top')
frame_3 = Frame(root)
frame_3.pack(side='top')
Label(frame_3, text="需求均值", font=("宋体", 15)).pack(side='left')
Entry(frame_3, textvariable=var[8], font=("宋体", 15), width=8, justify='center').pack(side='left')
var[8].set('1200')
Label(frame_3, text="需求方差", font=("宋体", 15), fg="black").pack(side='left')
Entry(frame_3, textvariable=var[9], font=("宋体", 15), width=8, justify='center').pack(side='left')
var[9].set('200')
frame_3_ = Frame(root)
frame_3_.pack(side='top')
Label(frame_3_, text="补货提前期均值", font=("宋体", 15)).pack(side='left')
Entry(frame_3_, textvariable=var[10], font=("宋体", 15), width=8, justify='center').pack(side='left')
var[10].set('5')
Label(frame_3_, text="补货提前期方差", font=("宋体", 15), fg="black").pack(side='left')
Entry(frame_3_, textvariable=var[11], font=("宋体", 15), width=8, justify='center').pack(side='left')
var[11].set('1.5')
frame_3_0 = Frame(root)
frame_3_0.pack(side='top')
Label(frame_3_0, text="预期服务水平", font=("宋体", 15), fg="black").pack(side='left')
Entry(frame_3_0, textvariable=var[12], font=("宋体", 15), width=8, justify='center').pack(side='left')
var[12].set('0.75')
Button(frame_3_0, text="安全库存图", font=("宋体", 12), fg="blue", command=mat).pack(side='left')

Label(root, text='-' * 50, font=("宋体", 15)).pack(side='top')
Label(root, text='牛鞭效应的制表与绘图', font=("宋体", 15), fg="green").pack(side='top')
frame_4 = Frame(root)
frame_4.pack(side='top')
Label(frame_4, text="中间商名称", font=("宋体", 15)).pack(side='top')
Entry(frame_4, font=("宋体", 15), fg="red")
Entry(frame_4, textvariable=var[13], font=("宋体", 15), width=40, justify='center').pack(side='top')
var[13].set('零售商 本地批发商 地区批发商 区域批发商')
Label(frame_4, text="客户购买量", font=("宋体", 15)).pack(side='top')
Entry(frame_4, textvariable=var[14], font=("宋体", 15), width=40, justify='center').pack(side='top')
var[14].set('100 105 100 100 100 100 100')
Button(frame_4, text="制表绘图", font=("宋体", 12), fg="blue", command=func).pack(side='top')
frame_4_ = Frame(root)
frame_4_.pack(side='top')
b1 = Button(frame_4, text="供应链成员购买或生产量变化折线图", font=("宋体", 12), fg="blue", state='disabled',
            command=func1)
b1.pack(side='top')
b2 = Button(frame_4, text="供应链购买或生产量变化折线图", font=("宋体", 12), fg="blue", state='disabled', command=func2)
b2.pack(side='top')
b3 = Button(frame_4, text="供应链购买或生产量波动百分比折线图", font=("宋体", 12), fg="blue", state='disabled',
            command=func3)
b3.pack(side='top')
b4 = Button(frame_4, text="最终牛鞭效应图", font=("宋体", 12), fg="blue", state='disabled', command=func4)
b4.pack(side='top')


def completion(matrix_half):  # 补全半个矩阵
    length = len(matrix_half)
    for i in range(length):
        for j in range(length):
            if matrix_half[i][j] == 1 and matrix_half[j][i] != 1:
                matrix_half[i][j] = 1 / matrix_half[j][i]
            if i == j:
                matrix_half[i][j] = 1
    return matrix_half


def matrix_transpose(matrix):  # 矩阵转置
    return [[matrix[j][i] for j in range(len(matrix))] for i in range(len(matrix[0]))]


def matrix_multiplication(matrix_2, matrix_1):  # 二维与一维的矩阵乘法
    return [sum(matrix_2[j][i] * matrix_1[i] for i in range(len(matrix_1))) for j in range(len(matrix_2))]


def summation(matrix_b):  # 求和法
    matrix_b = matrix_transpose(matrix_b)
    b_ = [[i for i in j] for j in matrix_b]  # 深度copy 等同于 b = copy.deepcopy(matrix_b)
    matrix_b = [[matrix_b[i][j] / sum(b_[i]) for j in range(len(matrix_b))] for i in range(len(matrix_b[0]))]  # 归一化
    matrix_b = matrix_transpose(matrix_b)
    v = [sum(i) for i in matrix_b]  # 按行求和得到v
    w = [i / sum(v) for i in v]  # 归一化得到w
    return v, w


def rooting(matrix_b):  # 求根法
    def q_root(list0):  # 相乘再开方
        quadrature = 1
        for i in list0:
            quadrature *= i
        root_ = quadrature ** (1 / len(list0))
        return root_

    v = [q_root(i) for i in matrix_b]  # 按行相乘再开方
    w = [i / sum(v) for i in v]  # 归一化得到w
    return v, w


def check(matrix_a):  # 一致性检验,1求根法，0求和法
    ri = {1: 0, 2: 0, 3: 0.58, 4: 0.92, 5: 1.12, 6: 1.24, 7: 1.32, 8: 1.41, 9: 1.45}  # RI表
    weight = rooting(matrix_a)[1] if method == 1 else summation(matrix_a)[1]
    a_w = matrix_multiplication(matrix_a, weight)
    lambda_max = sum([a_w[i] / weight[i] for i in range(len(weight))]) / len(a_w)
    if len(a_w) > 1:
        ci = (lambda_max - len(a_w)) / (len(a_w) - 1)  # CI值
    else:
        ci = 0
    ri = ri[len(a_w)]  # RI值
    if ri != 0:
        cr = ci / ri  # CR值
    else:
        cr = 0
    best = weight.index(max(weight))
    return a_w, weight, lambda_max, ci, ri, cr, best, True if cr < 0.1 else False


def check_all(matrix_, matrix_s):  # 层次总排序组合一致性检验
    w_ = check(matrix_)[0]  # 上一层的一致性检验值
    ci = sum([w_[i] * check(matrix_s[i])[3] for i in range(len(matrix_s))])
    ri = sum([w_[i] * check(matrix_s[i])[4] for i in range(len(matrix_s))])  # 这一层的一致性检验值权重和
    if ri != 0:
        cr = ci / ri
    else:
        cr = 0
    return cr, True if cr < 0.1 else False


def choice_best(target_, programmes_):
    target_w = check(target_)[1]
    programmes_w = matrix_transpose([check(i)[1] for i in programmes_])
    after_w = matrix_multiplication(programmes_w, target_w)
    best = after_w.index(max(after_w))
    cr, check_ = check_all(target_, programmes_)
    return target_w, programmes_w, after_w, best, cr, check_


def ahp_gui():
    root.destroy()
    root_new = Tk()
    root_new.title('AHP计算  by：wld')
    frame_first = Frame(root_new)
    frame_first.pack(side='top')
    var_o_s, var_w_s = StringVar(), StringVar()
    var_o_s.set('4')
    var_w_s.set('5')
    Label(frame_first, text='准则数：', font=('宋体', 15)).pack(side='left')
    entry001 = Entry(frame_first, textvariable=var_o_s, font=("宋体", 15), fg='blue', width=3, justify='center')
    entry001.pack(side='left')
    Label(frame_first, text='方案数：', font=('宋体', 15)).pack(side='left')
    entry002 = Entry(frame_first, textvariable=var_w_s, font=("宋体", 15), fg='blue', width=3, justify='center')
    entry002.pack(side='left')

    def third():
        option = int(eval(var_o_s.get()))  # 准则数
        ways = int(eval(var_w_s.get()))  # 方案数
        random_ = check_random.get()
        t_ = ['目标'] + ['目标']
        t_o = ['准则'] + [i.get() for i in var_o_names]
        o_w = ['方案'] + [i.get() for i in var_w_names]
        f = ['1', '1/2', '2', '1/3', '3', '1/4', '4', '1/5', '5', '1/6', '6', '1/7', '7', '1/8', '8', '1/9', '9',
             '1/10',
             '10', '1', '1/2', '2', '1/3', '3', '1/4', '4', '1/5', '5', '1/6', '6', '1/7', '7', '1/8', '8', '1/9', '9']

        def table(u, d):
            frame_n_t = Frame(frame_show)
            frame_n_t.pack(side='top')
            for one in range(len(u) - 1):
                frame_one = Frame(frame_n_t)
                frame_one.pack(side='left')
                frame_n = Frame(frame_one)
                frame_n.pack(side='top')
                num = [[Entry(frame_n, width=6, justify='center', font=("宋体", 15)) for _ in range(len(d))] for _ in d]
                for row in range(len(num)):
                    for column in range(len(num[0])):
                        if row == 0 and column == 0:
                            num[row][column].insert('end', u[one + 1])
                            num[row][column].config(state='disabled', bg='gray')
                        elif row == 0 and column != 0:
                            num[row][column].insert('end', d[column])
                            num[row][column].config(state='disabled', bg='gray')
                        elif row != 0 and column == 0:
                            num[row][column].insert('end', d[row])
                            num[row][column].config(state='disabled', bg='gray')
                        elif row < column:
                            num[row][column].insert('end',
                                                    str(f[(randint(0, int(max(ways, option))))]) if random_ else '1')
                        else:
                            num[row][column].insert('end', '1')
                            num[row][column].config(state='disabled', bg='gray')
                        num[row][column].grid(row=row, column=column)
                all_num.append(num)

        table(t_, t_o)
        if len(o_w) > 1:
            table(t_o, o_w)
        check_r.config(state='disabled')
        for i in entry003 + entry004:
            i.config(state='disabled')

        button001.config(state='disabled')
        frame_s = Frame(frame_show)
        frame_s.pack(side='top')
        Label(frame_s, text='计算方法：', font=('宋体', 15)).pack(side='left')
        global m
        m = IntVar()
        radio3_2 = Radiobutton(frame_s, text='方根法', font=('宋体', 15), variable=m, value=1)
        radio3_2.pack(side='left')
        radio3_1 = Radiobutton(frame_s, text='和积法', font=('宋体', 15), variable=m, value=0)
        radio3_1.pack(side='left')
        radio3_2.select()
        # 小数
        global entry_small_num
        Label(frame_s, text='显示小数：', font=('宋体', 15)).pack(side='left')
        entry_small_num = Entry(frame_s, font=("宋体", 15), fg='blue', width=3, justify='center')
        entry_small_num.insert(0, '4')
        entry_small_num.pack(side='left')
        Label(frame_s, text='位', font=('宋体', 15)).pack(side='left')
        Button(frame_show, text="计算", command=solve, font=('宋体', 15)).pack(side='bottom')

    def second():
        frame_second = Frame(root_new)
        frame_second.pack(side='top')
        global var_o_names, var_w_names, check_random, check_r, entry003, entry004, button001
        var_o_names = [StringVar() for _ in range(int(eval(var_o_s.get())))]
        var_w_names = [StringVar() for _ in range(int(eval(var_w_s.get())))]
        Label(frame_second, text='准则名', font=('宋体', 15)).pack(side='top')
        entry003 = []
        for i in range(len(var_o_names)):
            var_o_names[i].set(f'准则{i + 1}')
            entry003.append(Entry(frame_second, textvariable=var_o_names[i], font=("宋体", 15), fg='blue',
                                  width=10, justify='center'))
        for i in entry003:
            i.pack(side='left')
        frame_second_ = Frame(root_new)
        frame_second_.pack(side='top')
        Label(frame_second_, text='方案名', font=('宋体', 15)).pack(side='top')
        entry004 = []
        for i in range(len(var_w_names)):
            var_w_names[i].set(f'方案{i + 1}')
            entry004.append(Entry(frame_second_, textvariable=var_w_names[i], font=("宋体", 15), fg='blue',
                                  width=10, justify='center'))
        for i in entry004:
            i.pack(side='left')
        frame_second__ = Frame(root_new)
        frame_second__.pack(side='top')
        check_random = IntVar()
        check_r = Checkbutton(frame_second__, text='随机初始化数据', variable=check_random, font=('宋体', 12))
        check_r.pack(side='left')
        button001 = Button(frame_second__, text="下一步", command=third, font=('宋体', 15))
        button001.pack(side='left')

    def first():
        o_s = int(eval(var_o_s.get()))
        w_s = int(eval(var_w_s.get()))
        var_o_s.set(str(o_s))
        var_w_s.set(str(w_s))
        if (o_s <= 0) or (w_s < 0) or (o_s > 9) or (w_s > 9):
            messagebox.showerror(title='错误！', message='方案数和准则数限定取值0-9!')
            exit(0)
        if o_s * (w_s + 1) > 36:
            messagebox.showinfo(title='提示！',
                                message='准则和方案太多了！\n你的屏幕太小显示不过来！\n倒是也能算，只是你看不见我也没办法！')
        second()
        button0.config(state='disabled')
        entry001.config(state='disabled')
        entry002.config(state='disabled')

    button0 = Button(frame_first, text="下一步", command=first, font=('宋体', 15))
    button0.pack(side='left')

    # 整体展示
    frame_show = Frame(root_new)
    frame_show.pack(side='bottom')
    all_num = []

    def solve():
        global m, method
        method = int(m.get())
        option = int(eval(var_o_s.get()))  # 准则数
        ways = int(eval(var_w_s.get()))  # 方案数
        round_ = int(entry_small_num.get())
        t_ = ['目标'] + ['目标']
        t_o = ['准则'] + [i.get() for i in var_o_names]
        o_w = ['方案'] + [i.get() for i in var_w_names]
        names = ['目标/准则'] + [f'准则{i + 1}/方案' for i in range(option)]
        root_new_new = Tk()
        root_new_new.title('运算结果  by：wld')
        frame_show1 = Frame(root_new_new)
        frame_show1.pack(side='top')
        number = [[[eval(i.get()) for i in j[1:]] for j in k[1:]] for k in all_num]
        number = [completion(i) for i in number]
        numbers = []
        s = {0: '0', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 7: '7', 8: '8', 9: '9', 10: '10', 11: '11',
             12: '12', 13: '13', 14: '14', 15: '15', 16: '16', 17: '17', 18: '18', 19: '19', 20: '20', 21: '21',
             1 / 2: "1/2", 1 / 3: '1/3', 1 / 4: '1/4', 1 / 5: '1/5', 1 / 6: '1/6', 1 / 7: '1/7', 1 / 8: '1/8',
             1 / 9: '1/9', 1 / 10: '1/10', 1 / 11: '1/11', 1 / 12: '1/12', 1 / 13: '1/13', 1 / 14: '1/14',
             1 / 15: '1/15', 1 / 16: '1/16', 1 / 17: '1/17', 1 / 18: '1/18', 1 / 19: '1/19', 1 / 20: '1/20',
             1 / 21: '1/21'}

        def table1(u, d, h=0):
            frame_n_t1 = Frame(frame_show1)
            frame_n_t1.pack(side='top')
            for one in range(len(u) - 1):
                frame_one = Frame(frame_n_t1)
                frame_one.pack(side='left')
                frame_nums = Frame(frame_one)
                frame_nums.pack(side='top')
                frame_t = Frame(frame_one)
                frame_t.pack(side='left')
                nu = [[Entry(frame_nums, width=6, justify='center', font=("宋体", 15)) for _ in range(len(d))] for _ in
                      d]
                for row in range(len(nu)):
                    for column in range(len(nu[0])):
                        if row == 0 and column == 0:
                            nu[row][column].insert('end', u[one + 1])
                        elif row == 0 and column != 0:
                            nu[row][column].insert('end', d[column])
                        elif row != 0 and column == 0:
                            nu[row][column].insert('end', d[row])
                        else:
                            numb = (number[h][row - 1][column - 1])
                            try:
                                nu[row][column].insert('end', str(s[numb]))
                            except:
                                nu[row][column].insert('end', str(number[h][row - 1][column - 1]))
                        nu[row][column].grid(row=row, column=column)
                h += 1
                if h == 1:
                    global text0
                    text0 = Text(frame_t, font=("宋体", 15), width=6 * (len(d)), height=2 * (len(d) + 1))
                    text0.config(foreground='green')
                    text0.pack(side='right')
                text = Text(frame_t, font=("宋体", 15), width=6 * (len(d)), height=2 * (len(d) + 1))
                number0 = [[float(eval(i.get())) for i in j[1:]] for j in nu[1:]]
                numbers.append(number0)
                tip0 = ['A_w:', 'Weight:', 'λ_max:', 'CI:', 'RI:', 'CR:', 'Best:', '一致性检验:']
                info0 = check(number0)
                if h == 1:
                    text.insert('end', f'{names[0]}及一致性检验：' + '\n')
                else:
                    text.insert('end', f'{names[h - 1]}及一致性检验：' + '\n')
                for i in range(8):
                    if isinstance(info0[i], list):
                        text.insert('end', tip0[i] + str([round(j, round_) for j in info0[i]]) + '\n')
                    else:
                        if tip0[i] == 'Best:':
                            text.insert('end', tip0[i] + str(d[int(info0[i]) + 1]) + '\n')
                        else:
                            text.insert('end', tip0[i] + str(info0[i]) + '\n')
                if not info0[-1]:
                    text.config(foreground='red')
                text.pack()

        table1(t_, t_o)
        if len(o_w) > 1:
            table1(t_o, o_w, h=1)
        print()
        tip = ['W_0:', 'W_1:', 'W_2:', 'Best:', 'CR:', '整体一致性检验:']
        info = choice_best(numbers[0], numbers[1:])
        text0.insert('end', '最终结果及整体一致性检验：' + '\n')
        for i in range(6):
            if isinstance(info[i], list):
                if not isinstance(info[i][0], list):
                    text0.insert('end', tip[i] + str([round(j, round_) for j in info[i]]) + '\n')
                else:
                    text0.insert('end', tip[i] + str([[round(k, round_) for k in j] for j in info[i]]) + '\n')
            else:
                if tip[i] == 'Best:':
                    text0.insert('end', tip[i] + str(o_w[int(info[i]) + 1]) + '\n')
                else:
                    text0.insert('end', tip[i] + str(info[i]) + '\n')
        if not info[-1]:
            text0.config(foreground='red')
        text0.pack(side='right')


Label(root, text='-' * 50, font=("宋体", 15)).pack(side='top')
Label(root, text='层次分析法运算', font=("宋体", 15), fg="green").pack(side='top')
Button(root, text="AHP（测试窗口）", font=("宋体", 12), fg="blue", command=ahp_gui).pack()

root.mainloop()
